// [z-paging]scroll相关模块
import u from '.././z-paging-utils';
import Enum from '.././z-paging-enum';

// #ifdef APP-NVUE
const weexDom = weex.requireModule('dom');
// #endif
export default {
  props: {
    //使用页面滚动，默认为否，当设置为是时则使用页面的滚动而非此组件内部的scroll-view的滚动，使用页面滚动时z-paging无需设置确定的高度且对于长列表展示性能更高，但配置会略微繁琐
    usePageScroll: {
      type: Boolean,
      default: u.gc('usePageScroll', false),
    },
    //是否可以滚动，使用内置scroll-view和nvue时有效，默认为是
    scrollable: {
      type: Boolean,
      default: u.gc('scrollable', true),
    },
    //控制是否出现滚动条，默认为是
    showScrollbar: {
      type: Boolean,
      default: u.gc('showScrollbar', true),
    },
    //是否允许横向滚动，默认为否
    scrollX: {
      type: Boolean,
      default: u.gc('scrollX', false),
    },
    //iOS设备上滚动到顶部时是否允许回弹效果，默认为否。关闭回弹效果后可使滚动到顶部与下拉刷新更连贯，但是有吸顶view时滚动到顶部时可能出现抖动。
    scrollToTopBounceEnabled: {
      type: Boolean,
      default: u.gc('scrollToTopBounceEnabled', false),
    },
    //iOS设备上滚动到底部时是否允许回弹效果，默认为是。
    scrollToBottomBounceEnabled: {
      type: Boolean,
      default: u.gc('scrollToBottomBounceEnabled', true),
    },
    //在设置滚动条位置时使用动画过渡，默认为否
    scrollWithAnimation: {
      type: Boolean,
      default: u.gc('scrollWithAnimation', false),
    },
    //值应为某子元素id（id不能以数字开头）。设置哪个方向可滚动，则在哪个方向滚动到该元素
    scrollIntoView: {
      type: String,
      default: u.gc('scrollIntoView', ''),
    },
  },
  data() {
    return {
      scrollTop: 0,
      oldScrollTop: 0,
      scrollViewStyle: {},
      scrollViewContainerStyle: {},
      scrollViewInStyle: {},
      pageScrollTop: -1,
      scrollEnable: true,
      privateScrollWithAnimation: -1,
      cacheScrollNodeHeight: -1,
    };
  },
  watch: {
    oldScrollTop(newVal) {
      !this.usePageScroll && this._scrollTopChange(newVal, false);
    },
    pageScrollTop(newVal) {
      this.usePageScroll && this._scrollTopChange(newVal, true);
    },
    usePageScroll: {
      handler(newVal) {
        this.loaded && this.autoHeight && this._setAutoHeight(!newVal);
        // #ifdef H5
        if (newVal) {
          this.$nextTick(() => {
            const mainScrollRef = this.$refs['zp-scroll-view'].$refs.main;
            if (mainScrollRef) {
              mainScrollRef.style = {};
            }
          });
        }
        // #endif
      },
      immediate: true,
    },
    finalScrollTop(newVal) {
      if (!this.useChatRecordMode) {
        this.renderPropScrollTop = newVal < 6 ? 0 : 10;
      }
    },
  },
  computed: {
    finalScrollWithAnimation() {
      if (this.privateScrollWithAnimation !== -1) {
        const scrollWithAnimation = this.privateScrollWithAnimation === 1;
        this.privateScrollWithAnimation = -1;
        return scrollWithAnimation;
      }
      return this.scrollWithAnimation;
    },
    finalScrollViewStyle() {
      if (this.superContentZIndex != 1) {
        this.scrollViewStyle['z-index'] = this.superContentZIndex;
        this.scrollViewStyle['position'] = 'relative';
      }
      return this.scrollViewStyle;
    },
    finalScrollTop() {
      return this.usePageScroll ? this.pageScrollTop : this.oldScrollTop;
    },
    finalIsOldWebView() {
      return this.isOldWebView && !this.usePageScroll;
    },
  },
  methods: {
    //滚动到顶部，animate为是否展示滚动动画，默认为是
    scrollToTop(animate, checkReverse = true) {
      // #ifdef APP-NVUE
      if (checkReverse && this.useChatRecordMode) {
        if (!this.nIsFirstPageAndNoMore) {
          this.scrollToBottom(animate, false);
          return;
        }
      }
      // #endif
      this.$nextTick(() => {
        this._scrollToTop(animate, false);
        // #ifdef APP-NVUE
        if (this.nvueFastScroll && animate) {
          setTimeout(() => {
            this._scrollToTop(false, false);
          }, 150);
        }
        // #endif
      });
    },
    //滚动到底部，animate为是否展示滚动动画，默认为是
    scrollToBottom(animate, checkReverse = true) {
      // #ifdef APP-NVUE
      if (checkReverse && this.useChatRecordMode) {
        if (!this.nIsFirstPageAndNoMore) {
          this.scrollToTop(animate, false);
          return;
        }
      }
      // #endif
      this.$nextTick(() => {
        this._scrollToBottom(animate);
        // #ifdef APP-NVUE
        if (this.nvueFastScroll && animate) {
          setTimeout(() => {
            this._scrollToBottom(false);
          }, 150);
        }
        // #endif
      });
    },
    //滚动到指定view(vue中有效)。sel为需要滚动的view的id值，不包含"#"；offset为偏移量，单位为px；animate为是否展示滚动动画，默认为否
    scrollIntoViewById(sel, offset, animate) {
      this._scrollIntoView(sel, offset, animate);
    },
    //滚动到指定view(vue中有效)。nodeTop为需要滚动的view的top值(通过uni.createSelectorQuery()获取)；offset为偏移量，单位为px；animate为是否展示滚动动画，默认为否
    scrollIntoViewByNodeTop(nodeTop, offset, animate) {
      this.scrollTop = this.oldScrollTop;
      this.$nextTick(() => {
        this._scrollIntoViewByNodeTop(nodeTop, offset, animate);
      });
    },
    //滚动到指定位置(vue中有效)。y为与顶部的距离，单位为px；offset为偏移量，单位为px；animate为是否展示滚动动画，默认为否
    scrollToY(y, offset, animate) {
      this.scrollTop = this.oldScrollTop;
      this.$nextTick(() => {
        this._scrollToY(y, offset, animate);
      });
    },
    //滚动到指定view(nvue中有效)。index为需要滚动的view的index(第几个)；offset为偏移量，单位为px；animate为是否展示滚动动画，默认为否
    scrollIntoViewByIndex(index, offset, animate) {
      this._scrollIntoView(index, offset, animate);
    },
    //滚动到指定view(nvue中有效)。view为需要滚动的view(通过`this.$refs.xxx`获取)，不包含"#"；offset为偏移量，单位为px；animate为是否展示滚动动画，默认为否
    scrollIntoViewByView(view, offset, animate) {
      this._scrollIntoView(view, offset, animate);
    },
    //当使用页面滚动并且自定义下拉刷新时，请在页面的onPageScroll中调用此方法，告知z-paging当前的pageScrollTop，否则会导致在任意位置都可以下拉刷新
    updatePageScrollTop(value) {
      this.pageScrollTop = value;
    },
    //当使用页面滚动并且设置了slot="top"时，默认初次加载会自动获取其高度，并使内部容器下移，当slot="top"的view高度动态改变时，在其高度需要更新时调用此方法
    updatePageScrollTopHeight() {
      this._updatePageScrollTopOrBottomHeight('top');
    },
    //当使用页面滚动并且设置了slot="bottom"时，默认初次加载会自动获取其高度，并使内部容器下移，当slot="bottom"的view高度动态改变时，在其高度需要更新时调用此方法
    updatePageScrollBottomHeight() {
      this._updatePageScrollTopOrBottomHeight('bottom');
    },
    //更新slot="left"和slot="right"宽度，当slot="left"或slot="right"宽度动态改变时调用
    updateLeftAndRightWidth() {
      this.$nextTick(() => {
        this._updateLeftAndRightWidth();
      });
    },
    //更新z-paging内置scroll-view的scrollTop
    updateScrollViewScrollTop(scrollTop, animate = true) {
      this.privateScrollWithAnimation = animate ? 1 : 0;
      this.scrollTop = this.oldScrollTop;
      this.$nextTick(() => {
        this.scrollTop = scrollTop;
        this.oldScrollTop = this.scrollTop;
      });
    },

    //当滚动到顶部时
    _scrollToUpper() {
      this.$emit('scrolltoupper');
      this.$emit('scrollTopChange', 0);
      this.$nextTick(() => {
        this.oldScrollTop = 0;
      });
      if (!this.useChatRecordMode) return;
      if (this.loadingStatus === Enum.More.NoMore) return;
      this._onLoadingMore('click');
    },
    //滚动到顶部
    _scrollToTop(animate = true, isPrivate = true) {
      // #ifdef APP-NVUE
      const el = this.$refs['zp-n-list-top-tag'];
      if (this.usePageScroll) {
        this._getNodeClientRect('zp-page-scroll-top', false).then((node) => {
          const nodeHeight = node ? node[0].height : 0;
          weexDom.scrollToElement(el, {
            offset: -nodeHeight,
            animated: animate,
          });
        });
      } else {
        if (!this.isIos && this.nvueListIs === 'scroller') {
          this._getNodeClientRect('zp-n-refresh-container', false).then((node) => {
            const nodeHeight = node ? node[0].height : 0;
            weexDom.scrollToElement(el, {
              offset: -nodeHeight,
              animated: animate,
            });
          });
        } else {
          weexDom.scrollToElement(el, {
            offset: 0,
            animated: animate,
          });
        }
      }
      return;
      // #endif
      if (this.usePageScroll) {
        this.$nextTick(() => {
          uni.pageScrollTo({
            scrollTop: 0,
            duration: animate ? 100 : 0,
          });
        });
        return;
      }
      this.privateScrollWithAnimation = animate ? 1 : 0;
      this.scrollTop = this.oldScrollTop;
      this.$nextTick(() => {
        this.scrollTop = 0;
        this.oldScrollTop = this.scrollTop;
      });
    },
    //滚动到底部
    async _scrollToBottom(animate = true) {
      // #ifdef APP-NVUE
      const el = this.$refs['zp-n-list-bottom-tag'];
      if (el) {
        weexDom.scrollToElement(el, {
          offset: 0,
          animated: animate,
        });
      } else {
        u.consoleErr('滚动到底部失败，因为您设置了hideNvueBottomTag为true');
      }
      return;
      // #endif
      if (this.usePageScroll) {
        this.$nextTick(() => {
          uni.pageScrollTo({
            scrollTop: Number.MAX_VALUE,
            duration: animate ? 100 : 0,
          });
        });
        return;
      }
      try {
        this.privateScrollWithAnimation = animate ? 1 : 0;
        const pagingContainerNode = await this._getNodeClientRect('.zp-paging-container');
        const scrollViewNode = await this._getNodeClientRect('.zp-scroll-view');
        const pagingContainerH = pagingContainerNode ? pagingContainerNode[0].height : 0;
        const scrollViewH = scrollViewNode ? scrollViewNode[0].height : 0;
        if (pagingContainerH > scrollViewH) {
          this.scrollTop = this.oldScrollTop;
          this.$nextTick(() => {
            this.scrollTop = pagingContainerH - scrollViewH + this.virtualPlaceholderTopHeight;
            this.oldScrollTop = this.scrollTop;
          });
        }
      } catch (e) {}
    },
    //滚动到指定view
    _scrollIntoView(sel, offset = 0, animate = false, finishCallback) {
      try {
        this.scrollTop = this.oldScrollTop;
        this.$nextTick(() => {
          // #ifdef APP-NVUE
          const refs = this.$parent.$refs;
          if (!refs) return;
          const dataType = Object.prototype.toString.call(sel);
          let el = null;
          if (dataType === '[object Number]') {
            const els = refs[`z-paging-${sel}`];
            el = els ? els[0] : null;
          } else if (dataType === '[object Array]') {
            el = sel[0];
          } else {
            el = sel;
          }
          if (el) {
            weexDom.scrollToElement(el, {
              offset: -offset,
              animated: animate,
            });
          } else {
            u.consoleErr('在nvue中滚动到指定位置，cell必须设置 :ref="`z-paging-${index}`"');
          }
          return;
          // #endif
          if (sel.indexOf('#') != -1) {
            sel = sel.replace('#', '');
          }
          this._getNodeClientRect('#' + sel, false).then((node) => {
            if (node) {
              let nodeTop = node[0].top;
              this._scrollIntoViewByNodeTop(nodeTop, offset, animate);
              if (finishCallback) {
                finishCallback();
              }
            }
          });
        });
      } catch (e) {}
    },
    //通过nodeTop滚动到指定view
    _scrollIntoViewByNodeTop(nodeTop, offset = 0, animate = false) {
      this._scrollToY(nodeTop, offset, animate, true);
    },
    //滚动到指定位置
    _scrollToY(y, offset = 0, animate = false, addScrollTop = false) {
      this.privateScrollWithAnimation = animate ? 1 : 0;
      if (this.usePageScroll) {
        uni.pageScrollTo({
          scrollTop: y - offset,
          duration: animate ? 100 : 0,
        });
      } else {
        if (addScrollTop) {
          y += this.oldScrollTop;
        }
        this.scrollTop = y - offset;
        this.oldScrollTop = this.scrollTop;
      }
    },
    //scroll-view滚动中
    _scroll(e) {
      this.$emit('scroll', e);
      const scrollTop = e.detail.scrollTop;
      // #ifndef APP-NVUE
      this.finalUseVirtualList && this._updateVirtualScroll(scrollTop, this.oldScrollTop - scrollTop);
      // #endif
      this.oldScrollTop = scrollTop;
      const scrollDiff = e.detail.scrollHeight - this.oldScrollTop;
      !this.isIos && this._checkScrolledToBottom(scrollDiff);
    },
    //scrollTop改变时触发
    _scrollTopChange(newVal, isPageScrollTop) {
      this.$emit('scrollTopChange', newVal);
      this.$emit('update:scrollTop', newVal);
      this._checkShouldShowBackToTop(newVal);
      const scrollTop = this.isIos ? (newVal > 5 ? 6 : 0) : newVal;
      if (isPageScrollTop) {
        this.wxsPageScrollTop = scrollTop;
      } else {
        this.wxsScrollTop = scrollTop;
      }
    },
    //更新使用页面滚动时slot="top"或"bottom"插入view的高度
    _updatePageScrollTopOrBottomHeight(type) {
      // #ifndef APP-NVUE
      if (!this.usePageScroll) return;
      // #endif
      this._doCheckScrollViewShouldFullHeight(this.realTotalData);
      const node = `.zp-page-${type}`;
      const marginText = `margin${type.slice(0, 1).toUpperCase() + type.slice(1)}`;
      let safeAreaInsetBottomAdd = this.safeAreaInsetBottom;
      this.$nextTick(() => {
        let delayTime = 0;
        // #ifdef MP-BAIDU || APP-NVUE
        delayTime = 50;
        // #endif
        setTimeout(() => {
          this._getNodeClientRect(node).then((res) => {
            if (res) {
              let pageScrollNodeHeight = res[0].height;
              if (type === 'bottom') {
                if (safeAreaInsetBottomAdd) {
                  pageScrollNodeHeight += this.safeAreaBottom;
                }
              } else {
                this.cacheTopHeight = pageScrollNodeHeight;
              }
              this.$set(this.scrollViewStyle, marginText, `${pageScrollNodeHeight}px`);
            } else if (safeAreaInsetBottomAdd) {
              this.$set(this.scrollViewStyle, marginText, `${this.safeAreaBottom}px`);
            }
          });
        }, delayTime);
      });
    },
    //获取slot="left"和slot="right"宽度并且更新布局
    _updateLeftAndRightWidth() {
      if (!this.finalIsOldWebView) return;
      this.$nextTick(() => {
        let delayTime = 0;
        // #ifdef MP-BAIDU
        delayTime = 10;
        // #endif
        setTimeout(() => {
          ['left', 'right'].map((position) => {
            this._getNodeClientRect(`.zp-page-${position}`).then((res) => {
              this.$set(this.scrollViewContainerStyle, position, res ? res[0].width + 'px' : '0px');
            });
          });
        }, delayTime);
      });
    },
  },
};
